/***************************************************************************************
 The copyright in this software is being made available under the BSD License, included
 below. This software may be subject to other third party rights,including patent rights,
 and no such rights are granted under this license.

 Regents of the Tsinghua University, Peking University, Zhejiang University, HKUST
 Tsinghua University, Peking University, Zhejiang University, HKUST 2011

 Copyright (c) 2011, Regents of the Tsinghua University, Peking University, Zhejiang
 University, HKUST. All Rights Reserved.

 Redistribution and use in source and binary forms, with or without modification, are
 permitted provided that the following conditions are met:
   * Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   * Neither the names of the copyright holders nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 OF SUCH DAMAGE.
***************************************************************************************/


#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <memory.h>

#include "contributors.h"
#include "defines.h"
#include "global.h"
#include "vlc.h"
#include "block.h"
#include "golomb.h"

#ifdef RDO_Q
#include "rdoq.h"
#endif

#define Q_BITS          21
#define EP (edgepixels+20)

#if defined(WIN32) && !defined(__MINGW32__)
#define int16 __int16
#else
#define int16 int16_t
#endif


unsigned short Q_TAB[64] =
{
    32768, 29775, 27554, 25268, 23170, 21247, 19369, 17770,
    16302, 15024, 13777, 12634, 11626, 10624, 9742, 8958,
    8192, 7512, 6889, 6305, 5793, 5303, 4878, 4467,
    4091, 3756, 3444, 3161, 2894, 2654, 2435, 2235,
    2048, 1878, 1722, 1579, 1449, 1329, 1218, 1117,
    1024, 939, 861, 790, 724, 664, 609, 558,
    512, 470, 430, 395, 362, 332, 304, 279,
    256, 235, 215, 197, 181, 166, 152, 140
};

unsigned short IQ_TAB[64] =
{

    32768, 36061, 38968, 42495, 46341, 50535, 55437, 60424,
    32932, 35734, 38968, 42495, 46177, 50535, 55109, 59933,
    65535, 35734, 38968, 42577, 46341, 50617, 55027, 60097,
    32809, 35734, 38968, 42454, 46382, 50576, 55109, 60056,
    65535, 35734, 38968, 42495, 46320, 50515, 55109, 60076,
    65535, 35744, 38968, 42495, 46341, 50535, 55099, 60087,
    65535, 35734, 38973, 42500, 46341, 50535, 55109, 60097,
    32771, 35734, 38965, 42497, 46341, 50535, 55109, 60099
};

short IQ_SHIFT[64] =
{
    15, 15, 15, 15, 15, 15, 15, 15,
    14, 14, 14, 14, 14, 14, 14, 14,
    14, 13, 13, 13, 13, 13, 13, 13,
    12, 12, 12, 12, 12, 12, 12, 12,
    12, 11, 11, 11, 11, 11, 11, 11,
    11, 10, 10, 10, 10, 10, 10, 10,
    10, 9, 9, 9, 9, 9, 9, 9,
    8, 8, 8, 8, 8, 8, 8, 8
};

const byte QP_SCALE_CR[64] =
{
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
    10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
    20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
    30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
    40, 41, 42, 42, 43, 43, 44, 44, 45, 45,
    46, 46, 47, 47, 48, 48, 48, 49, 49, 49,
    50, 50, 50, 51,
};


const int ZD_MAT[8][8] =
{
    {8, 8, 8, 8, 8, 8, 8, 8},
    {10, 9, 6, 2, -2, -6, -9, -10},
    {10, 4, -4, -10, -10, -4, 4, 10},
    {9, -2, -10, -6, 6, 10, 2, -9},
    {8, -8, -8, 8, 8, -8, -8, 8},
    {6, -10, 2, 9, -9, -2, 10, -6},
    {4, -10, 10, -4, -4, 10, -10, 4},
    {2, -6, 9, -10, 10, -9, 6, -2}
};

int ScaleM[4][4] =
{
    {32768, 37958, 36158, 37958},
    {37958, 43969, 41884, 43969},
    {36158, 41884, 39898, 41884},
    {37958, 43969, 41884, 43969}
};


const int DCT_16[16][16]=
{
    {     32,    32,    32,    32,    32,    32,    32,    32,    32,    32,    32,    32,    32,    32,    32,    32  },
    {     45,    43,    40,    35,    29,    21,    13,     4,    -4,   -13,   -21,   -29,   -35,   -40,   -43,   -45  },
    {     44,    38,    25,     9,    -9,   -25,   -38,   -44,   -44,   -38,   -25,    -9,     9,    25,    38,    44  },
    {     43,    29,     4,   -21,   -40,   -45,   -35,   -13,    13,    35,    45,    40,    21,    -4,   -29,   -43  },
    {     42,    17,   -17,   -42,   -42,   -17,    17,    42,    42,    17,   -17,   -42,   -42,   -17,    17,    42  },
    {     40,     4,   -35,   -43,   -13,    29,    45,    21,   -21,   -45,   -29,    13,    43,    35,    -4,   -40  },
    {     38,    -9,   -44,   -25,    25,    44,     9,   -38,   -38,     9,    44,    25,   -25,   -44,    -9,    38  },
    {     35,   -21,   -43,     4,    45,    13,   -40,   -29,    29,    40,   -13,   -45,    -4,    43,    21,   -35  },
    {     32,   -32,   -32,    32,    32,   -32,   -32,    32,    32,   -32,   -32,    32,    32,   -32,   -32,    32  },
    {     29,   -40,   -13,    45,    -4,   -43,    21,    35,   -35,   -21,    43,     4,   -45,    13,    40,   -29  },
    {     25,   -44,     9,    38,   -38,    -9,    44,   -25,   -25,    44,    -9,   -38,    38,     9,   -44,    25  },
    {     21,   -45,    29,    13,   -43,    35,     4,   -40,    40,    -4,   -35,    43,   -13,   -29,    45,   -21  },
    {     17,   -42,    42,   -17,   -17,    42,   -42,    17,    17,   -42,    42,   -17,   -17,    42,   -42,    17  },
    {     13,   -35,    45,   -40,    21,     4,   -29,    43,   -43,    29,    -4,   -21,    40,   -45,    35,   -13  },
    {      9,   -25,    38,   -44,    44,   -38,    25,    -9,    -9,    25,   -38,    44,   -44,    38,   -25,     9  },
    {      4,   -13,    21,   -29,    35,   -40,    43,   -45,    45,   -43,    40,   -35,    29,   -21,    13,    -4  },
};
const int DCT_8[8][8]=
{
    {     45,    45,    45,    45,    45,    45,    45,    45  },
    {     63,    53,    36,    12,   -12,   -36,   -53,   -63  },
    {     59,    24,   -24,   -59,   -59,   -24,    24,    59  },
    {     53,   -12,   -63,   -36,    36,    63,    12,   -53  },
    {     45,   -45,   -45,    45,    45,   -45,   -45,    45  },
    {     36,   -63,    12,    53,   -53,   -12,    63,   -36  },
    {     24,   -59,    59,   -24,   -24,    59,   -59,    24  },
    {     12,   -36,    53,   -63,    63,   -53,    36,   -12  },
};
const int DCT_4[4][4]=
{
    {     64,    64,    64,    64  },
    {     84,    35,   -35,   -84  },
    {     64,   -64,   -64,    64  },
    {     35,   -84,    84,   -35  },
};
const int ZIGZAG_SCAN_16x16[2][256][2] =
{
    {
        { 0, 0},{ 0, 1},{ 1, 0},{ 2, 0},{ 3, 0},{ 4, 0},{ 0, 2},{ 1, 1},{ 2, 1},{ 3, 1},{ 4, 1},{ 5, 0},{ 6, 0},{ 7, 0},{ 8, 0},{ 0, 3},
        { 1, 2},{ 2, 2},{ 3, 2},{ 4, 2},{ 5, 1},{ 6, 1},{ 7, 1},{ 8, 1},{ 9, 0},{10, 0},{11, 0},{12, 0},{15, 0},{14, 0},{13, 0},{12, 1},
        {11, 1},{10, 1},{ 9, 1},{ 8, 2},{ 7, 2},{ 6, 2},{ 5, 2},{ 4, 3},{ 3, 3},{ 2, 3},{ 1, 3},{ 0, 4},{ 0, 5},{ 1, 4},{ 2, 4},{ 3, 4},
        { 4, 4},{ 5, 3},{ 6, 3},{ 7, 3},{ 8, 3},{ 9, 2},{10, 2},{11, 2},{12, 2},{13, 1},{14, 1},{15, 1},{15, 2},{14, 2},{13, 2},{12, 3},
        {11, 3},{10, 3},{ 9, 3},{ 8, 4},{ 7, 4},{ 6, 4},{ 5, 4},{ 4, 5},{ 3, 5},{ 2, 5},{ 1, 5},{ 0, 6},{ 0, 7},{ 1, 6},{ 2, 6},{ 3, 6},
        { 4, 6},{ 5, 5},{ 6, 5},{ 7, 5},{ 8, 5},{ 9, 4},{10, 4},{11, 4},{12, 4},{13, 3},{14, 3},{15, 3},{15, 4},{14, 4},{13, 4},{12, 5},
        {11, 5},{10, 5},{ 9, 5},{ 8, 6},{ 7, 6},{ 6, 6},{ 5, 6},{ 4, 7},{ 3, 7},{ 2, 7},{ 1, 7},{ 0, 8},{ 0, 9},{ 1, 8},{ 2, 8},{ 3, 8},
        { 4, 8},{ 5, 7},{ 6, 7},{ 7, 7},{ 8, 7},{ 9, 6},{10, 6},{11, 6},{12, 6},{13, 5},{14, 5},{15, 5},{15, 6},{14, 6},{13, 6},{12, 7},
        {11, 7},{10, 7},{ 9, 7},{ 8, 8},{ 7, 8},{ 6, 8},{ 5, 8},{ 4, 9},{ 3, 9},{ 2, 9},{ 1, 9},{ 0,10},{ 0,11},{ 1,10},{ 2,10},{ 3,10},
        { 4,10},{ 5, 9},{ 6, 9},{ 7, 9},{ 8, 9},{ 9, 8},{10, 8},{11, 8},{12, 8},{13, 7},{14, 7},{15, 7},{15, 8},{14, 8},{13, 8},{12, 9},
        {11, 9},{10, 9},{ 9, 9},{ 8,10},{ 7,10},{ 6,10},{ 5,10},{ 4,11},{ 3,11},{ 2,11},{ 1,11},{ 0,12},{ 0,13},{ 1,12},{ 2,12},{ 3,12},
        { 4,12},{ 5,11},{ 6,11},{ 7,11},{ 8,11},{ 9,10},{10,10},{11,10},{12,10},{13, 9},{14, 9},{15, 9},{15,10},{14,10},{13,10},{12,11},
        {11,11},{10,11},{ 9,11},{ 8,12},{ 7,12},{ 6,12},{ 5,12},{ 4,13},{ 3,13},{ 2,13},{ 1,13},{ 0,14},{ 0,15},{ 1,14},{ 2,14},{ 3,14},
        { 4,14},{ 5,13},{ 6,13},{ 7,13},{ 8,13},{ 9,12},{10,12},{11,12},{12,12},{13,11},{14,11},{15,11},{15,12},{14,12},{13,12},{12,13},
        {11,13},{10,13},{ 9,13},{ 8,14},{ 7,14},{ 6,14},{ 5,14},{ 4,15},{ 3,15},{ 2,15},{ 1,15},{ 5,15},{ 6,15},{ 7,15},{ 8,15},{ 9,14},
        {10,14},{11,14},{12,14},{13,13},{14,13},{15,13},{15,14},{14,14},{13,14},{12,15},{11,15},{10,15},{ 9,15},{13,15},{14,15},{15,15}
    },
    {
        { 0, 0},{ 1, 0},{ 0, 1},{ 0, 2},{ 1, 1},{ 2, 0},{ 3, 0},{ 2, 1},{ 1, 2},{ 0, 3},{ 0, 4},{ 1, 3},{ 2, 2},{ 3, 1},{ 4, 0},{ 5, 0},
        { 4, 1},{ 3, 2},{ 2, 3},{ 1, 4},{ 0, 5},{ 0, 6},{ 1, 5},{ 2, 4},{ 3, 3},{ 4, 2},{ 5, 1},{ 6, 0},{ 7, 0},{ 6, 1},{ 5, 2},{ 4, 3},
        { 3, 4},{ 2, 5},{ 1, 6},{ 0, 7},{ 0, 8},{ 1, 7},{ 2, 6},{ 3, 5},{ 4, 4},{ 5, 3},{ 6, 2},{ 7, 1},{ 8, 0},{ 9, 0},{ 8, 1},{ 7, 2},
        { 6, 3},{ 5, 4},{ 4, 5},{ 3, 6},{ 2, 7},{ 1, 8},{ 0, 9},{ 0,10},{ 1, 9},{ 2, 8},{ 3, 7},{ 4, 6},{ 5, 5},{ 6, 4},{ 7, 3},{ 8, 2},
        { 9, 1},{10, 0},{11, 0},{10, 1},{ 9, 2},{ 8, 3},{ 7, 4},{ 6, 5},{ 5, 6},{ 4, 7},{ 3, 8},{ 2, 9},{ 1,10},{ 0,11},{ 0,12},{ 1,11},
        { 2,10},{ 3, 9},{ 4, 8},{ 5, 7},{ 6, 6},{ 7, 5},{ 8, 4},{ 9, 3},{10, 2},{11, 1},{12, 0},{13, 0},{12, 1},{11, 2},{10, 3},{ 9, 4},
        { 8, 5},{ 7, 6},{ 6, 7},{ 5, 8},{ 4, 9},{ 3,10},{ 2,11},{ 1,12},{ 0,13},{ 0,14},{ 1,13},{ 2,12},{ 3,11},{ 4,10},{ 5, 9},{ 6, 8},
        { 7, 7},{ 8, 6},{ 9, 5},{10, 4},{11, 3},{12, 2},{13, 1},{14, 0},{15, 0},{14, 1},{13, 2},{12, 3},{11, 4},{10, 5},{ 9, 6},{ 8, 7},
        { 7, 8},{ 6, 9},{ 5,10},{ 4,11},{ 3,12},{ 2,13},{ 1,14},{ 0,15},{ 1,15},{ 2,14},{ 3,13},{ 4,12},{ 5,11},{ 6,10},{ 7, 9},{ 8, 8},
        { 9, 7},{10, 6},{11, 5},{12, 4},{13, 3},{14, 2},{15, 1},{15, 2},{14, 3},{13, 4},{12, 5},{11, 6},{10, 7},{ 9, 8},{ 8, 9},{ 7,10},
        { 6,11},{ 5,12},{ 4,13},{ 3,14},{ 2,15},{ 3,15},{ 4,14},{ 5,13},{ 6,12},{ 7,11},{ 8,10},{ 9, 9},{10, 8},{11, 7},{12, 6},{13, 5},
        {14, 4},{15, 3},{15, 4},{14, 5},{13, 6},{12, 7},{11, 8},{10, 9},{ 9,10},{ 8,11},{ 7,12},{ 6,13},{ 5,14},{ 4,15},{ 5,15},{ 6,14},
        { 7,13},{ 8,12},{ 9,11},{10,10},{11, 9},{12, 8},{13, 7},{14, 6},{15, 5},{15, 6},{14, 7},{13, 8},{12, 9},{11,10},{10,11},{ 9,12},
        { 8,13},{ 7,14},{ 6,15},{ 7,15},{ 8,14},{ 9,13},{10,12},{11,11},{12,10},{13, 9},{14, 8},{15, 7},{15, 8},{14, 9},{13,10},{12,11},
        {11,12},{10,13},{ 9,14},{ 8,15},{ 9,15},{10,14},{11,13},{12,12},{13,11},{14,10},{15, 9},{15,10},{14,11},{13,12},{12,13},{11,14},
        {10,15},{11,15},{12,14},{13,13},{14,12},{15,11},{15,12},{14,13},{13,14},{12,15},{13,15},{14,14},{15,13},{15,14},{14,15},{15,15}
    }
};
const int ZIGZAG_SCAN_4x4[2][16][2] =
{
    {
        {0,0},{0,1},{1,0},{0,2},
        {0,3},{1,1},{1,2},{1,3},
        {2,0},{2,1},{2,2},{2,3},
        {3,0},{3,1},{3,2},{3,3}
    },
    {
        {0,0},{1,0},{0,1},{0,2},
        {1,1},{2,0},{3,0},{2,1},
        {1,2},{0,3},{1,3},{2,2},
        {3,1},{3,2},{2,3},{3,3}
    }
};

extern cs_ptr_t create_coding_state();
extern void delete_coding_state( cs_ptr_t );
extern void store_coding_state( cs_ptr_t );
extern void reset_coding_state( cs_ptr_t );

extern const int RF_SCAN[2][64][2];

#define B8_SIZE 8

static int sign( int a, int b )
{
    int x;
    x = RFM_ABS( a );

    if ( b >= 0 )
        return x;
    else
        return -x;
}


void transform_b8( int** curr_blk )
{
    int i, j ;
    int temp1[8], temp2[8], temp ;

    for( i=0; i<8; i++ )
    {
        // step 1
        temp1[0] = curr_blk[i][0] + curr_blk[i][7] ;
        temp1[7] = curr_blk[i][0] - curr_blk[i][7] ;
        temp1[1] = curr_blk[i][1] + curr_blk[i][6] ;
        temp1[6] = curr_blk[i][1] - curr_blk[i][6] ;
        temp1[2] = curr_blk[i][2] + curr_blk[i][5] ;
        temp1[5] = curr_blk[i][2] - curr_blk[i][5] ;
        temp1[3] = curr_blk[i][3] + curr_blk[i][4] ;
        temp1[4] = curr_blk[i][3] - curr_blk[i][4] ;

        // step 2
        temp2[0] = temp1[0] + temp1[3] ;
        temp2[3] = temp1[0] - temp1[3] ;
        temp2[1] = temp1[1] + temp1[2] ;
        temp2[2] = temp1[1] - temp1[2] ;
        temp     = ( temp1[4] + temp1[7] )*201>>8 ;
        temp2[4] = ( temp1[4]*100>>8 ) + temp ;
        temp2[7] = ( temp1[7]*502>>8 ) - temp ;
        temp     = ( temp1[5] + temp1[6] )*141>>9 ;
        temp2[5] = ( temp1[5]*569>>9 ) + temp ;
        temp2[6] = ( temp1[6]*851>>9 ) - temp ;

        // step 3
        temp1[0] = ( temp2[0] + temp2[1] )*181>>7 ;
        temp1[4] = ( temp2[0] - temp2[1] )*181>>7 ;
        temp     = ( temp2[2] + temp2[3] )*196>>8 ;
        temp1[2] = ( temp2[3]*277>>8 ) + temp ;
        temp1[6] = temp - ( temp2[2]*669>>8 ) ;

        temp1[7] = temp2[4] + temp2[6] ;
        temp1[1] = temp2[7] + temp2[5] ;
        temp1[5] = ( temp2[4] - temp2[6] )*181>>7 ;
        temp1[3] = ( temp2[7] - temp2[5] )*181>>7 ;

        temp = temp1[7] + temp1[1] ;
        temp1[7] = temp1[1] - temp1[7] ;
        temp1[1] = temp ;

        for( j=0; j<8; j++ )
        {
            curr_blk[i][j] = temp1[j] ;
        }
    }
    // vertical
    for( i=0; i<8; i++ )
    {
        // step 1
        temp1[0] = curr_blk[0][i] + curr_blk[7][i] ;
        temp1[7] = curr_blk[0][i] - curr_blk[7][i] ;
        temp1[1] = curr_blk[1][i] + curr_blk[6][i] ;
        temp1[6] = curr_blk[1][i] - curr_blk[6][i] ;
        temp1[2] = curr_blk[2][i] + curr_blk[5][i] ;
        temp1[5] = curr_blk[2][i] - curr_blk[5][i] ;
        temp1[3] = curr_blk[3][i] + curr_blk[4][i] ;
        temp1[4] = curr_blk[3][i] - curr_blk[4][i] ;

        // step 2
        temp2[0] = temp1[0] + temp1[3] ;
        temp2[3] = temp1[0] - temp1[3] ;
        temp2[1] = temp1[1] + temp1[2] ;
        temp2[2] = temp1[1] - temp1[2] ;
        temp     = ( temp1[4] + temp1[7] )*201>>8 ;
        temp2[4] = ( temp1[4]*100>>8 ) + temp ;
        temp2[7] = ( temp1[7]*502>>8 ) - temp ;
        temp     = ( temp1[5] + temp1[6] )*141>>9 ;
        temp2[5] = ( temp1[5]*569>>9 ) + temp ;
        temp2[6] = ( temp1[6]*851>>9 ) - temp ;

        // step 3
        temp1[0] = ( temp2[0] + temp2[1] )*181>>7 ;
        temp1[4] = ( temp2[0] - temp2[1] )*181>>7 ;
        temp     = ( temp2[2] + temp2[3] )*196>>8 ;
        temp1[2] = ( temp2[3]*277>>8 ) + temp ;
        temp1[6] = temp - ( temp2[2]*669>>8 ) ;


        temp1[7] = temp2[4] + temp2[6] ;
        temp1[1] = temp2[7] + temp2[5] ;
        temp1[5] = ( temp2[4] - temp2[6] )*181>>7 ;
        temp1[3] = ( temp2[7] - temp2[5] )*181>>7 ;

        temp = temp1[7] + temp1[1] ;
        temp1[7] = temp1[1] - temp1[7] ;
        temp1[1] = temp ;

        for( j=0; j<8; j++ )
        {
            if( temp1[j]>0 )
            {
                curr_blk[j][i] = ( temp1[j]+8 )>>4 ;
            }
            else
            {
                curr_blk[j][i] = -( ( -temp1[j]+8 )>>4 ) ;
            }
        }
    }
}

void quant_b8( int qp, int intra, int** curr_blk )    //intra_flag=>mode
{
    int x, y;
    int val, temp;
    int qp_const;

    /****************
    adaptive rounding by liwr N11
    ****************/
    int qdiff;  //adaptive rounding
    int y_left, x_top;
    int yuv;

    if ( input->AdaptiveRounding )
    {
        y_left = img->blk_idx >=4 ? 0 : ( img->blk_idx/2 )*8;
        x_top  = img->blk_idx >=4 ? 0 : ( img->blk_idx%2 )*8;
        yuv    = img->blk_idx <4  ? 0 : img->blk_idx==4?1:2;

        for ( y=0; y<8; y++ )
        {
            for ( x=0; x<8; x++ )
            {
                val = curr_blk[y][x];
                temp = RFM_ABS( val );
                qp_const = qoffset[yuv][img->type][intra][y+y_left][x+x_top];
                curr_blk[y][x] = sign( ( ( temp * Q_TAB[qp]+qp_const )>>15 ), val ) ;
                qdiff=temp*Q_TAB[qp]-( RFM_ABS( curr_blk[y][x] )<<15 );
                img->qadjust[yuv][y+y_left][x+x_top] = ( curr_blk[y][x]==0 ) ? 0 :( ( input->AdaptRndWeight[img->type+3*( yuv!=0 )]*qdiff + ( 1<<15 ) ) >> 16 );
            }
        }
    }
    else
    {
        if( intra )
            qp_const = ( 1<<15 )*10/31;
        else
            qp_const = ( 1<<15 )*10/62;
        for ( y=0; y<8; y++ )
        {
            for ( x=0; x<8; x++ )
            {
                val = curr_blk[y][x];
                temp = RFM_ABS( val );
                curr_blk[y][x] = sign( ( ( temp * Q_TAB[qp]+qp_const )>>15 ), val ) ;
            }
        }
    }
}

void inv_transform_b8( int** curr_blk )
{
    int i, j ;
    int temp1[8], temp2[8];

    for( i=0; i<8; i++ )
    {
        // step 1
        temp1[0] = ( curr_blk[i][0] + curr_blk[i][4] )*181>>7 ;
        temp1[1] = ( curr_blk[i][0] - curr_blk[i][4] )*181>>7 ;
        temp1[2] = ( curr_blk[i][2]*196>>8 ) - ( curr_blk[i][6]*473>>8 ) ;
        temp1[3] = ( curr_blk[i][2]*473>>8 ) + ( curr_blk[i][6]*196>>8 ) ;

        temp2[4] = curr_blk[i][1] - curr_blk[i][7] ;
        temp2[7] = curr_blk[i][1] + curr_blk[i][7] ;
        temp2[5] = curr_blk[i][3]*181>>7 ;
        temp2[6] = curr_blk[i][5]*181>>7 ;
        temp1[4] = temp2[4] + temp2[6] ;
        temp1[5] = temp2[7] - temp2[5] ;
        temp1[6] = temp2[4] - temp2[6] ;
        temp1[7] = temp2[7] + temp2[5] ;

        // step 2
        temp2[0] = temp1[0] + temp1[3] ;
        temp2[3] = temp1[0] - temp1[3] ;
        temp2[1] = temp1[1] + temp1[2] ;
        temp2[2] = temp1[1] - temp1[2] ;
        temp2[4] = ( temp1[4]*301>>8 ) - ( temp1[7]*201>>8 ) ;
        temp2[7] = ( temp1[4]*201>>8 ) + ( temp1[7]*301>>8 ) ;
        temp2[5] = ( temp1[5]*710>>9 ) - ( temp1[6]*141>>9 ) ;
        temp2[6] = ( temp1[5]*141>>9 ) + ( temp1[6]*710>>9 ) ;

        // step 3
        curr_blk[i][0] = temp2[0] + temp2[7] ;
        curr_blk[i][7] = temp2[0] - temp2[7] ;
        curr_blk[i][1] = temp2[1] + temp2[6] ;
        curr_blk[i][6] = temp2[1] - temp2[6] ;
        curr_blk[i][2] = temp2[2] + temp2[5] ;
        curr_blk[i][5] = temp2[2] - temp2[5] ;
        curr_blk[i][3] = temp2[3] + temp2[4] ;
        curr_blk[i][4] = temp2[3] - temp2[4] ;
    }
    for( i=0; i<8; i++ )
    {
        // step 1
        temp1[0] = ( curr_blk[0][i] + curr_blk[4][i] )*181>>7 ;
        temp1[1] = ( curr_blk[0][i] - curr_blk[4][i] )*181>>7 ;
        temp1[2] = ( curr_blk[2][i]*196>>8 ) - ( curr_blk[6][i]*473>>8 ) ;
        temp1[3] = ( curr_blk[2][i]*473>>8 ) + ( curr_blk[6][i]*196>>8 ) ;

        temp2[4] = curr_blk[1][i] - curr_blk[7][i] ;
        temp2[7] = curr_blk[1][i] + curr_blk[7][i] ;
        temp2[5] = curr_blk[3][i]*181>>7 ;
        temp2[6] = curr_blk[5][i]*181>>7 ;
        temp1[4] = temp2[4] + temp2[6] ;
        temp1[5] = temp2[7] - temp2[5] ;
        temp1[6] = temp2[4] - temp2[6] ;
        temp1[7] = temp2[7] + temp2[5] ;

        // step 2
        temp2[0] = temp1[0] + temp1[3] ;
        temp2[3] = temp1[0] - temp1[3] ;
        temp2[1] = temp1[1] + temp1[2] ;
        temp2[2] = temp1[1] - temp1[2] ;
        temp2[4] = ( temp1[4]*301>>8 ) - ( temp1[7]*201>>8 ) ;
        temp2[7] = ( temp1[4]*201>>8 ) + ( temp1[7]*301>>8 ) ;
        temp2[5] = ( temp1[5]*710>>9 ) - ( temp1[6]*141>>9 ) ;
        temp2[6] = ( temp1[5]*141>>9 ) + ( temp1[6]*710>>9 ) ;

        // step 3
        curr_blk[0][i] = temp2[0] + temp2[7] ;
        curr_blk[7][i] = temp2[0] - temp2[7] ;
        curr_blk[1][i] = temp2[1] + temp2[6] ;
        curr_blk[6][i] = temp2[1] - temp2[6] ;
        curr_blk[2][i] = temp2[2] + temp2[5] ;
        curr_blk[5][i] = temp2[2] - temp2[5] ;
        curr_blk[3][i] = temp2[3] + temp2[4] ;
        curr_blk[4][i] = temp2[3] - temp2[4] ;

        for( j=0; j<8; j++ )
        {
            if( curr_blk[j][i]>0 )
            {
                curr_blk[j][i] = ( curr_blk[j][i] + 16 )>>5 ;
            }
            else
            {
                curr_blk[j][i] = -( ( -curr_blk[j][i] + 16 )>>5 ) ;
            }
        }
    }

}

int scanquant_b8( int qp, int intra_flag, int block8x8, int** curr_blk, int *cbp, int *cbp_16x16 )
{
    int  run;
    int  x, y, dc_pred=0;
    int  icoef, ipos;
    int  b8_y, b8_x;
    int  coeff_cost    = 0;
    int* ACLevel;
    int* ACRun;
    int  curr_val;
    int val, shift, QPI;
    int clip1 = -( 1<<( 8+7 ) );
    int clip2 = ( 1<<( 8+7 ) )-1;
    byte **pred;
    int b_frame = img->type == B_IMG;
    macroblock_t * currMB = &img->mb_data[img->curr_mb_nr];


#ifdef RDO_Q
    int levelTrellis[64] = {0} ;
    levelDataStruct levelData[64] ;
    int lambda_RDO_Q = img->lambda_mode ;
    int temp_blk[8][8] ;
    for( x=0; x<8; x++ )
    {
        for( y=0; y<8; y++ )
        {
            temp_blk[x][y] = curr_blk[x][y] ;
        }
    }
#endif

    img->blk_idx = block8x8;
    y = block8x8 / 2;
    x = block8x8 % 2;
    b8_y = 8 * y;
    b8_x = 8 * x;
    shift = IQ_SHIFT[qp];
    QPI   = IQ_TAB[qp];

    quant_b8( qp, intra_flag, curr_blk );

    if( intra_flag )
    {
        pred = intra_pred;
        if ( block8x8<4 )
        {
            currMB->y_dc[y][x] = img->b8_residual[0][0];
            currMB->y_dc_diff[y][x] = currMB->y_dc[y][x];
            currMB->y_dc_pred[y][x] = 0;
            decide_y_intra_b8_mode( block8x8 );
        }
        if ( block8x8 < 4 )
        {
            curr_blk[0][0] = currMB->y_dc_diff[y][x];
            dc_pred = currMB->y_dc_pred[y][x];
        }
        else if ( block8x8 == 4 )
        {
            curr_blk[0][0] = currMB->uv_dc_diff[0];
            dc_pred = currMB->uv_dc_pred[0];
        }
        else if ( block8x8 == 5 )
        {
            curr_blk[0][0] = currMB->uv_dc_diff[1];
            dc_pred = currMB->uv_dc_pred[1];
        }
    }
    else
        pred = inter_pred;


#ifdef RDO_Q
    if( input->UseRDO_Q8&&( block8x8<4 ) )
    {
        cs_ptr_t cs_sb = create_coding_state();
        store_coding_state( cs_sb );
#if INTRA_MODE_ADAPTIVE
        if( intra_flag )
            write_luma_intra_mode( currMB->b8mode[block8x8/2][block8x8%2],block8x8,0 ); //RDO write mode
#endif
		RDO_Q_init8x8( temp_blk, qp, intra_flag, block8x8, levelData ) ;
        RDO_Quant8x8( levelData, levelTrellis, block8x8, intra_flag, lambda_RDO_Q ) ;
        reset_coding_state( cs_sb );
        delete_coding_state( cs_sb );
    }
#endif

    ACLevel  = img->cofAC[block8x8][0][0];
    ACRun    = img->cofAC[block8x8][0][1];
    for ( x=0; x<65; x++ )
        ACRun[x] = ACLevel[x] = 0;

    run  = -1;
    ipos = 0;

    for ( icoef=0; icoef<64; icoef++ )
    {
        run++;
        x = RF_SCAN[1 /*img->picture_structure*/][icoef][0];
        y = RF_SCAN[1 /*img->picture_structure*/][icoef][1];

#ifdef RDO_Q
        if( input->UseRDO_Q8&&( block8x8<4 ) )
        {
            if( !x&&!y&&intra_flag )
                curr_val = curr_blk[0][0] ;
            else
                curr_val = sign( levelTrellis[icoef],temp_blk[y][x] ); //levelTrellis[icof] ;
        }
        else
        {
            curr_val = curr_blk[y][x];
        }
#else
        curr_val = curr_blk[y][x];
#endif

        if ( curr_val != 0 )
        {
            ACLevel[ipos] = curr_val;
            ACRun[ipos]   = run;

            if ( b_frame && RFM_ABS( ACLevel[ipos] )==1 )
                coeff_cost +=( b_frame )? 1 : RF_COEFF_COST[run];
            else
                coeff_cost = MAX_VALUE;

            val = curr_val ;
            if ( intra_flag && !y && !x )
            {
                if ( block8x8 < 4 )
                {
                    val += dc_pred;
                }
                else if ( block8x8 == 4 )
                {
                    val += dc_pred;
                }
                else if ( block8x8 == 5 )
                {
                    val += dc_pred;
                }
            }
            curr_blk[y][x] = sign( ( RFM_ABS( val )*QPI+( 1<<( shift-2 ) ) )>>( shift-1 ), val ) ;
            curr_blk[y][x] = RFM_CLIP3( curr_blk[y][x],clip1,clip2 );

            run = -1;
            ipos++;
        }
        else
        {
            if ( intra_flag && !y && !x )
            {
                val = dc_pred;
                curr_blk[y][x] = sign( ( RFM_ABS( val )*QPI+( 1<<( shift-2 ) ) )>>( shift-1 ), val ) ;
                curr_blk[y][x] = RFM_CLIP3( curr_blk[y][x],clip1,clip2 );
            }
            else
            {
                curr_blk[y][x] = 0 ;
            }
        }
    }

    if ( ipos>0 )
    {
        if ( block8x8 <= 3 )
            ( *cbp ) |= ( 1<<block8x8 );
        else
        {
            ( *cbp ) |= ( 1<<( block8x8 ) );
            ( *cbp_16x16 ) |= ( 1<<( block8x8-3 ) ); //  cbp_16
        }
    }
    inv_transform_b8( curr_blk );

    if ( block8x8 <= 3 )
    {
        for ( y=0; y<8; y++ )
        {
            for ( x=0; x<8; x++ )
            {
                curr_val = pred[b8_y+y][b8_x+x] + curr_blk[y][x];
                p_img_y_rec[img->pix_y+b8_y+y][img->pix_x+b8_x+x] = RFM_CLIP3( curr_val, 0, 255 );
            }
        }
    }
    else
    {
        for ( y=0; y<8; y++ )
        {
            for ( x=0; x<8; x++ )
            {
                curr_val = pred[y][x] + curr_blk[y][x];
                p_img_uv_rec[( block8x8-4 )&1][img->pix_c_y+y][img->pix_c_x+x] = RFM_CLIP3( curr_val, 0, 255 );
            }
        }
    }
    return coeff_cost;
}


int find_sad_8x8( int iMode, int iSizeX, int iSizeY, int iOffX, int iOffY, int m7[MB_BLOCK_SIZE][MB_BLOCK_SIZE] )
{
    int i, j;
    int bmode;
    int ishift = 0;
    int sad = 0;

    assert( ( iSizeX + iOffX ) <= MB_BLOCK_SIZE );
    assert( ( iSizeY + iOffY ) <= MB_BLOCK_SIZE );

    switch ( iMode )
    {
        case 0:
            for ( j = iOffY; j < iOffY + iSizeY; j++ )
                for ( i = iOffX; i < iOffX + iSizeX; i++ )
                    sad += RFM_ABS( m7[j][i] );
            break;

        case 1:
            bmode = iSizeX + iSizeY;
            if ( bmode < 24 )
            {
                sad = sad_hadamard( iSizeY, iSizeX, iOffY, iOffX, m7 );
                ishift = 2;
                sad = ( sad + ( 1 << ( ishift - 1 ) ) ) >> ishift;
            }
            else
            {
                switch ( bmode )
                {
                    case 24:
                        sad = sad_hadamard( 8, 8, iOffY, iOffX, m7 );
                        sad += sad_hadamard( 8, 8, iOffY + ( ( iSizeY == 16 ) ? 8 : 0 ), iOffX + ( ( iSizeX == 16 ) ? 8 : 0 ), m7 );
                        ishift = 2;
                        break;
                    case 32:
                        sad = sad_hadamard( 8, 8, 0, 0, m7 );
                        sad += sad_hadamard( 8, 8, 8, 0, m7 );
                        sad += sad_hadamard( 8, 8, 0, 8, m7 );
                        sad += sad_hadamard( 8, 8, 8, 8, m7 );
                        ishift = 2;
                        break;
                    default:
                        assert( 0 == 1 );
                }
                sad = ( sad + ( 1 << ( ishift - 1 ) ) ) >> ishift;
            }
            break;

        default:
            assert( 0 == 1 );
    }

    return sad;
}


int sad_hadamard( int iSizeX, int iSizeY, int iOffX, int iOffY, int m7[MB_BLOCK_SIZE][MB_BLOCK_SIZE] )
{
    int i, j, ii;
    int m1[MB_BLOCK_SIZE][MB_BLOCK_SIZE];
    int m2[MB_BLOCK_SIZE][MB_BLOCK_SIZE];
    int m3[MB_BLOCK_SIZE][MB_BLOCK_SIZE];
    int sad = 0;

    int iy[MB_BLOCK_SIZE] =
    {
        iOffY, iOffY, iOffY, iOffY,
        iOffY, iOffY, iOffY, iOffY,
        iOffY, iOffY, iOffY, iOffY,
        iOffY, iOffY, iOffY, iOffY
    };


    assert( ( ( iOffX == 0 ) || ( iSizeX <= 8 ) ) && ( ( iOffY == 0 ) || ( iSizeY <= 8 ) ) );

    for ( j = 1; j < iSizeY; j++ )
        iy[j] += j;

    if ( iSizeY == 4 )
        for ( i = 0; i < iSizeX; i++ )
        {
            ii = i + iOffX;

            m1[i][0] = m7[ii][iy[0]] + m7[ii][iy[3]];
            m1[i][1] = m7[ii][iy[1]] + m7[ii][iy[2]];
            m1[i][2] = m7[ii][iy[1]] - m7[ii][iy[2]];
            m1[i][3] = m7[ii][iy[0]] - m7[ii][iy[3]];

            m3[i][0] = m1[i][0] + m1[i][1];
            m3[i][1] = m1[i][0] - m1[i][1];
            m3[i][2] = m1[i][2] + m1[i][3];
            m3[i][3] = m1[i][3] - m1[i][2];
        }
    else
        for ( i = 0; i < iSizeX; i++ )
        {
            ii = i + iOffX;

            m1[i][0] = m7[ii][iy[0]] + m7[ii][iy[4]];
            m1[i][1] = m7[ii][iy[1]] + m7[ii][iy[5]];
            m1[i][2] = m7[ii][iy[2]] + m7[ii][iy[6]];
            m1[i][3] = m7[ii][iy[3]] + m7[ii][iy[7]];
            m1[i][4] = m7[ii][iy[0]] - m7[ii][iy[4]];
            m1[i][5] = m7[ii][iy[1]] - m7[ii][iy[5]];
            m1[i][6] = m7[ii][iy[2]] - m7[ii][iy[6]];
            m1[i][7] = m7[ii][iy[3]] - m7[ii][iy[7]];

            m2[i][0] = m1[i][0] + m1[i][2];
            m2[i][1] = m1[i][1] + m1[i][3];
            m2[i][2] = m1[i][0] - m1[i][2];
            m2[i][3] = m1[i][1] - m1[i][3];
            m2[i][4] = m1[i][4] + m1[i][6];
            m2[i][5] = m1[i][5] + m1[i][7];
            m2[i][6] = m1[i][4] - m1[i][6];
            m2[i][7] = m1[i][5] - m1[i][7];

            m3[i][0] = m2[i][0] + m2[i][1];
            m3[i][1] = m2[i][0] - m2[i][1];
            m3[i][2] = m2[i][2] + m2[i][3];
            m3[i][3] = m2[i][2] - m2[i][3];
            m3[i][4] = m2[i][4] + m2[i][5];
            m3[i][5] = m2[i][4] - m2[i][5];
            m3[i][6] = m2[i][6] + m2[i][7];
            m3[i][7] = m2[i][6] - m2[i][7];
        }

    if ( iSizeX == 4 )
        for ( j = 0; j < iSizeY; j++ )
        {
            m1[0][j] = m3[0][j] + m3[3][j];
            m1[1][j] = m3[1][j] + m3[2][j];
            m1[2][j] = m3[1][j] - m3[2][j];
            m1[3][j] = m3[0][j] - m3[3][j];

            m2[0][j] = m1[0][j] + m1[1][j];
            m2[1][j] = m1[0][j] - m1[1][j];
            m2[2][j] = m1[2][j] + m1[3][j];
            m2[3][j] = m1[3][j] - m1[2][j];

            for ( i = 0; i < iSizeX; i++ )
                sad += RFM_ABS( m2[i][j] );
        }
    else
        for ( j = 0; j < iSizeY; j++ )
        {
            m2[0][j] = m3[0][j] + m3[4][j];
            m2[1][j] = m3[1][j] + m3[5][j];
            m2[2][j] = m3[2][j] + m3[6][j];
            m2[3][j] = m3[3][j] + m3[7][j];
            m2[4][j] = m3[0][j] - m3[4][j];
            m2[5][j] = m3[1][j] - m3[5][j];
            m2[6][j] = m3[2][j] - m3[6][j];
            m2[7][j] = m3[3][j] - m3[7][j];

            m1[0][j] = m2[0][j] + m2[2][j];
            m1[1][j] = m2[1][j] + m2[3][j];
            m1[2][j] = m2[0][j] - m2[2][j];
            m1[3][j] = m2[1][j] - m2[3][j];
            m1[4][j] = m2[4][j] + m2[6][j];
            m1[5][j] = m2[5][j] + m2[7][j];
            m1[6][j] = m2[4][j] - m2[6][j];
            m1[7][j] = m2[5][j] - m2[7][j];

            m2[0][j] = m1[0][j] + m1[1][j];
            m2[1][j] = m1[0][j] - m1[1][j];
            m2[2][j] = m1[2][j] + m1[3][j];
            m2[3][j] = m1[2][j] - m1[3][j];
            m2[4][j] = m1[4][j] + m1[5][j];
            m2[5][j] = m1[4][j] - m1[5][j];
            m2[6][j] = m1[6][j] + m1[7][j];
            m2[7][j] = m1[6][j] - m1[7][j];

            for ( i = 0; i < iSizeX; i++ )
                sad += RFM_ABS( m2[i][j] );
        }
    return ( sad );
}

int write_luma_coeff_b8_qcoder( int b8 )
{
    int no_bits               = 0;
    macroblock_t *currMB      = &img->mb_data[img->curr_mb_nr];
    int *bitCount             = currMB->bit_counter;

    int inumcoeff = 65;
    int icoef;
    int ipos;
    int b4;
    int *ACLevel;
    int *ACRun;

    int coeff[64];
    int coeff_ptr = 0;
    int pos = 0;
    int eobFlag = 0;
    int code_len = 0;

    static const int blk_table[4] = {0, -1, -1, -1};

    int isintra = ( currMB->mb_type==I8MB||currMB->mb_type==I4MB );

    memset( coeff, 0, 64*sizeof( int ) );
    pos = 0;
    coeff_ptr = 0;
    inumcoeff = 64;

    /************************************************************************/
    /*                   8x8                                                */
    /************************************************************************/
    if (  currMB->transform_4x4[b8] == 0 )
    {
        b4 = blk_table[0];
        ipos = 0;
        ACLevel = img->cofAC[b8][b4][0];
        ACRun = img->cofAC[b8][b4][1];

        // Accumulate Run-Level info
        for ( icoef = 0; icoef < inumcoeff; icoef++ )
        {
            if ( !ACLevel[icoef] )
                break;
            pos += ACRun[icoef];
            coeff[pos++] = ACLevel[icoef];
            coeff_ptr++;
        }

        for( ipos=0; ipos < pos; )
        {
            code_len = qcoder_encode_eobflag_8x8( qcoder, eobFlag, ipos );
            no_bits += code_len;
            bitCount[BITS_COEFF_Y_MB] += code_len;

            if( !eobFlag )
            {
                do
                {
                    code_len = qcoder_encode_luma_8x8_coeff( qcoder, ipos, coeff[ipos], isintra );
                    no_bits += code_len;
                    bitCount[BITS_COEFF_Y_MB] += code_len;
                    ipos++;
                }
                while( coeff[ipos-1]==0 );
            }
        }
        if( ipos!=64 )
        {
            eobFlag = 1;
            code_len = qcoder_encode_eobflag_8x8( qcoder, eobFlag, ipos );
            no_bits += code_len;
            bitCount[BITS_COEFF_Y_MB] += code_len;
        }
    }
    /************************************************************************/
    /*                   4x4                                                */
    /************************************************************************/
    else if(  currMB->transform_4x4[b8] == 1 )
    {
        inumcoeff = 16;
        for( b4=0; b4<4; b4++ )
        {
            memset( coeff, 0, 64*sizeof( int ) );
            coeff_ptr=0;
            pos = 0;
            eobFlag = 0;
            ipos  = 0;

            ACLevel  =  img->cofAC[b8][b4][0];
            ACRun  =  img->cofAC[b8][b4][1];

            // Accumulate Run-Level info
            for ( icoef = 0; icoef < inumcoeff; icoef++ )
            {
                if ( !ACLevel[icoef] )
                    break;
                pos += ACRun[icoef];
                coeff[pos++] = ACLevel[icoef];
                coeff_ptr++;
            }

            for( ipos=0; ipos < pos; )
            {
                code_len = qcoder_encode_eobflag_4x4( qcoder, eobFlag, ipos );
                no_bits += code_len;
                bitCount[BITS_COEFF_Y_MB] += code_len;

                if( !eobFlag )
                {
                    do
                    {
                        code_len = qcoder_encode_luma_4x4_coeff( qcoder, ipos, coeff[ipos], isintra );
                        no_bits += code_len;
                        bitCount[BITS_COEFF_Y_MB] += code_len;
                        ipos++;
                    }
                    while( coeff[ipos-1]==0 );
                }
            }
            if( ipos!=16 )
            {
                eobFlag = 1;
                code_len = qcoder_encode_eobflag_4x4( qcoder, eobFlag, ipos );
                no_bits += code_len;
                bitCount[BITS_COEFF_Y_MB] += code_len;
            }

        }
    }
    return no_bits;
}

int write_chroma_coeff_b8_qcoder( int b8 )
{
    int no_bits = 0;
    int mb_nr = img->curr_mb_nr;
    macroblock_t* currMB = &img->mb_data[mb_nr];

    int* bitCount = currMB->bit_counter;

    int iblk, i, j, b4, ipos;
    int icoef, inumcoeff;
    int *ACLevel;
    int *ACRun;
    static int coeff[64];
    static int coeff_ptr = 0;
    static int pos = 0;
    int eobFlag = 0;
    int code_len = 0;

    static const int blk_table[4] = { 0, -1, -1, -1 };
    int isintra = ( currMB->mb_type==I8MB||currMB->mb_type==I4MB );

    memset( coeff, 0, 64*sizeof( int ) );
    pos = 0;
    coeff_ptr = 0;

    inumcoeff = 64;


    if ( 1 )
    {
        for ( iblk = 0; iblk < 1; iblk++ )
        {
            i = 0;
            j = ( i & ~1 ) << 1;
            i = ( i & 1 ) << 2;
            if ( ( i < 0 ) || ( i >= 8 ) || ( j < 0 ) || ( j >= 8 ) )
                continue;
            b4 = blk_table[iblk];

            ipos = 0;
            ACLevel = img->cofAC[b8][b4][0];
            ACRun = img->cofAC[b8][b4][1];

            // Accumulate Run-Level info
            for ( icoef = 0; icoef < inumcoeff; icoef++ )
            {
                if ( !ACLevel[icoef] )
                    break;
                pos += ACRun[icoef];
                coeff[pos++] = ACLevel[icoef];
                coeff_ptr++;
            }

            if( pos !=0 )
            {
                for( ipos=0; ipos<pos; )
                {
                    code_len = qcoder_encode_eobflag_chroma( qcoder, eobFlag, ipos );
                    bitCount[BITS_COEFF_UV_MB] += code_len;
                    no_bits += code_len;

                    if( !eobFlag )
                    {
                        do
                        {
                            code_len = qcoder_encode_chroma_8x8_coeff( qcoder, ipos, coeff[ipos], isintra );
                            bitCount[BITS_COEFF_UV_MB] += code_len;
                            no_bits += code_len;
                            ipos++;
                        }
                        while( coeff[ipos-1]==0 );
                    }
                }
                if( ipos!=64 )
                {
                    eobFlag = 1;
                    code_len = qcoder_encode_eobflag_chroma( qcoder, eobFlag, ipos );
                    bitCount[BITS_COEFF_UV_MB] += code_len;
                    no_bits += code_len;
                }
            }
            else
            {
                eobFlag = 1;
                code_len = qcoder_encode_eobflag_chroma( qcoder, eobFlag, 0 );
                bitCount[BITS_COEFF_UV_MB] += code_len;
                no_bits += code_len;
            }
        }
    }

    return no_bits;
}





#ifdef RDO_Q
extern void qcoder_encode_symbol( qcoder_env_t*, prob_context_t*, int );

static double qcoder_est_one_symbol( qcoder_env_t* qcoder, prob_context_t *ctx, int symbol )
{
    int lps_interval = ctx->prob_fsm[ctx->state].lps_interval;
    int interval = qcoder->interval;
    //int interval = 0xAAAA;
    int mps_interval = interval - lps_interval;
    int b_mps = ctx->mps == symbol;
    double rate;

    if ( ( b_mps && lps_interval<mps_interval ) || ( !b_mps && lps_interval>mps_interval ) )
    {
        rate = log( ( double )interval/( double )mps_interval ) / log( 2.0 );
    }
    else
    {
        rate = log( ( double )interval/( double )lps_interval ) / log( 2.0 );
    }
    return rate;
}

static double qcoder_est_eobflag_8x8( qcoder_env_t* qcoder, int eob, int idx )
{
    prob_context_t *eob_ctx = &qcoder->cx_eob_flag_8x8[idx];
    return qcoder_est_one_symbol( qcoder, eob_ctx, eob );
}

static double qcoder_est_luma_8x8_coeff( qcoder_env_t* qcoder, int idx, int value, int* no_bit, int isintra )
{
    int num_coeff_b8_cx_r = ( isintra )?NUM_COEFF_B8_CX_QCODER_R_INTRA:NUM_COEFF_B8_CX_QCODER_R_INTER;
    int num_contexts = ( isintra )?NUM_COEFF_B8_CX_QCODER_C_INTRA:NUM_COEFF_B8_CX_QCODER_C_INTER;
    int n = 0, k = 0;
    double rate;

    prob_context_t *contexts = &( qcoder->cx_luma_8x8[idx<( num_coeff_b8_cx_r-1 )  ? idx : ( num_coeff_b8_cx_r-1 )][0] );
    qcoder->nbits = 0;

    rate = qcoder_est_one_symbol( qcoder, &( contexts[n] ), value == 0 );
    qcoder_encode_symbol( qcoder, &( contexts[n] ), value == 0 );
    if ( value == 0 ) return rate;
    if ( n < num_contexts - 1 ) n++;
    rate += qcoder_est_one_symbol( qcoder, &( contexts[n] ), value < 0 );
    qcoder_encode_symbol( qcoder, &( contexts[n] ), value < 0 );
    if ( value < 0 ) value = -value;
    if ( n < num_contexts - 1 ) n++;
    value -= 1;
    while ( value >= ( 1 << k ) )
    {
        rate += qcoder_est_one_symbol( qcoder, &( contexts[n] ), 1 );
        qcoder_encode_symbol( qcoder, &( contexts[n] ), 1 );
        value -= 1 << k++;
        if ( n < num_contexts - 1 ) n++;
    }

    // code zero to mark end of exponent
    rate += qcoder_est_one_symbol( qcoder, &( contexts[n] ), 0 );
    qcoder_encode_symbol( qcoder, &( contexts[n] ), 0 );
    // advance to next context if sufficient contexts
    if ( n < num_contexts - 1 ) n++;

    while ( k-- > 0 )
    {
        rate += qcoder_est_one_symbol( qcoder, &( qcoder->eq_prob_context ), ( ( value & ( 1 << k ) ) != 0 ) );
        qcoder_encode_symbol( qcoder, &( qcoder->eq_prob_context ), ( ( value & ( 1 << k ) ) != 0 ) );
        if ( n < num_contexts - 1 ) n++;
    }
    *no_bit = qcoder->nbits;
    return rate;
}

double est_luma_coeff_b8_qcoder( int b8, int intra )
{
    int no_bits               = 0;
    macroblock_t *currMB      = &img->mb_data[img->curr_mb_nr];
    int *bitCount             = currMB->bit_counter;
    double rate = 0, rate_len;

    int inumcoeff = 65;
    int icoef;
    int ipos;
    int i, j;
    int b4;
    int *ACLevel;
    int *ACRun;
    int coeff[64];
    int coeff_ptr = 0;
    int pos = 0;
    int eobFlag = 0;
    int code_len = 0;
    int cbp8 = 0 ;


    static const int blk_table[4] = {0, -1, -1, -1};

    memset( coeff, 0, 64*sizeof( int ) );
    pos = 0;
    coeff_ptr = 0;
    inumcoeff = 64;

    ACLevel = img->cofAC[b8][0][0];
    for ( icoef = 0; icoef < inumcoeff; icoef++ )
    {
        if ( ACLevel[icoef] )
        {
            cbp8 = 1 ;
            break ;
        }
    }
    if ( cbp8 )
    {
        i = 0;
        j = ( i & ~1 ) << 1;
        i = ( i & 1 ) << 2;
        if ( ( i < 0 ) || ( i >= 8 ) || ( j < 0 ) || ( j >= 8 ) )
            return 0;
        b4 = blk_table[0];
        ipos = 0;
        ACLevel = img->cofAC[b8][b4][0];
        ACRun = img->cofAC[b8][b4][1];

        // Accumulate Run-Level info
        for ( icoef = 0; icoef < inumcoeff; icoef++ )
        {
            if ( !ACLevel[icoef] )
                break;
            pos += ACRun[icoef];
            coeff[pos++] = ACLevel[icoef];
            coeff_ptr++;
        }

        for( ipos=0; ipos < pos; )
        {
            rate_len = qcoder_est_eobflag_8x8( qcoder, eobFlag, ipos );
            rate += rate_len;
            code_len = qcoder_encode_eobflag_8x8( qcoder, eobFlag, ipos );
            no_bits += code_len;
            bitCount[BITS_COEFF_Y_MB] += code_len;

            if( !eobFlag )
            {
                do
                {
                    rate_len = qcoder_est_luma_8x8_coeff( qcoder, ipos, coeff[ipos], &code_len, intra );
                    rate += rate_len;
                    no_bits += code_len;
                    bitCount[BITS_COEFF_Y_MB] += code_len;
                    ipos++;
                }
                while( coeff[ipos-1]==0 );
            }
        }
        if( ipos!=64 )
        {
            eobFlag = 1;
            rate_len = qcoder_est_eobflag_8x8( qcoder, eobFlag, ipos );
            rate += rate_len;
            code_len = qcoder_encode_eobflag_8x8( qcoder, eobFlag, ipos );
            no_bits += code_len;
            bitCount[BITS_COEFF_Y_MB] += code_len;
        }
    }
    else
    {
        rate = qcoder_est_eobflag_8x8( qcoder, 1, 0 );
        no_bits = qcoder_encode_eobflag_8x8( qcoder, 1, 0 );
    }
    return rate;
}


int est_chroma_coeff_b8_qcoder( int b8, int intra )
{
    int no_bits = 0;
    int mb_nr = img->curr_mb_nr;
    macroblock_t* currMB = &img->mb_data[mb_nr];

    int* bitCount = currMB->bit_counter;

    int iblk, i, j, b4, ipos;
    int icoef, inumcoeff;
    int *ACLevel;
    int *ACRun;
    static int coeff[64];
    static int coeff_ptr = 0;
    static int pos = 0;
    int eobFlag = 0;
    int flag = 0 ;
    int code_len = 0;

    static const int blk_table[4] = { 0, -1, -1, -1 };

    memset( coeff, 0, 64*sizeof( int ) );
    pos = 0;
    coeff_ptr = 0;

    inumcoeff = 64;

    //if (b8 < 6)
    //  flag = (cbp & (1 << b8));

    ACLevel = img->cofAC[b8][0][0];
    for ( icoef = 0; icoef < inumcoeff; icoef++ )
    {
        if ( ACLevel[icoef] )
        {
            flag = 1 ;
            break ;
        }
    }

    if ( flag )
    {
        for ( iblk = 0; iblk < 1; iblk++ )
        {
            i = 0;
            j = ( i & ~1 ) << 1;
            i = ( i & 1 ) << 2;
            if ( ( i < 0 ) || ( i >= 8 ) || ( j < 0 ) || ( j >= 8 ) )
                continue;
            b4 = blk_table[iblk];

            ipos = 0;
            ACLevel = img->cofAC[b8][b4][0];
            ACRun = img->cofAC[b8][b4][1];

            // Accumulate Run-Level info
            for ( icoef = 0; icoef < inumcoeff; icoef++ )
            {
                if ( !ACLevel[icoef] )
                    break;
                pos += ACRun[icoef];
                coeff[pos++] = ACLevel[icoef];
                coeff_ptr++;
            }

            for( ipos=0; ipos<pos; )
            {
                code_len = qcoder_encode_eobflag_chroma( qcoder, eobFlag, ipos );
                bitCount[BITS_COEFF_UV_MB] += code_len;
                no_bits += code_len;

                if( !eobFlag )
                {
                    do
                    {
                        code_len = qcoder_encode_chroma_8x8_coeff( qcoder, ipos, coeff[ipos], intra );
                        bitCount[BITS_COEFF_UV_MB] += code_len;
                        no_bits += code_len;
                        ipos++;
                    }
                    while( coeff[ipos-1]==0 );
                }
            }
            if( ipos!=64 )
            {
                eobFlag = 1;
                code_len = qcoder_encode_eobflag_chroma( qcoder, eobFlag, ipos );
                bitCount[BITS_COEFF_UV_MB] += code_len;
                no_bits += code_len;
            }
        }
    }
    else
    {
        no_bits = qcoder_encode_eobflag_chroma( qcoder, 1, 0 );
    }

    return no_bits;
}


int est_luma_coeff_b4_qcoder( int b8, int b4, int intra )
{
    int no_bits               = 0;
    macroblock_t *currMB      = &img->mb_data[img->curr_mb_nr];
    int *bitCount             = currMB->bit_counter;

    int inumcoeff ;
    int icoef;
    int ipos;

    int *ACLevel;
    int *ACRun;
    int coeff[16];
    int coeff_ptr = 0;
    int pos = 0;
    int eobFlag = 0;
    int code_len = 0;
    int cbp4 = 0 ;

    memset( coeff, 0, 16*sizeof( int ) );

    inumcoeff = 16 ;

    ACLevel  =  img->cofAC[b8][b4][0];
    for ( icoef = 0; icoef < inumcoeff; icoef++ )
    {
        if ( ACLevel[icoef] )
        {
            cbp4 = 1 ;
            break ;
        }
    }

    if ( cbp4 )
    {
        ipos  = 0;

        ACLevel  =  img->cofAC[b8][b4][0];
        ACRun  =  img->cofAC[b8][b4][1];

        // Accumulate Run-Level info
        for ( icoef = 0; icoef < inumcoeff; icoef++ )
        {
            if ( !ACLevel[icoef] )
                break;
            pos += ACRun[icoef];
            coeff[pos++] = ACLevel[icoef];
            coeff_ptr++;
        }

        for( ipos=0; ipos < pos; )
        {
            code_len = qcoder_encode_eobflag_4x4( qcoder, eobFlag, ipos );
            no_bits += code_len;
            bitCount[BITS_COEFF_Y_MB] += code_len;

            if( !eobFlag )
            {
                do
                {
                    code_len = qcoder_encode_luma_4x4_coeff( qcoder, ipos, coeff[ipos], intra );
                    no_bits += code_len;
                    bitCount[BITS_COEFF_Y_MB] += code_len;
                    ipos++;
                }
                while( coeff[ipos-1]==0 );
            }
        }
        if( ipos!=16 )
        {
            eobFlag = 1;
            code_len = qcoder_encode_eobflag_4x4( qcoder, eobFlag, ipos );
            no_bits += code_len;
            bitCount[BITS_COEFF_Y_MB] += code_len;
        }
    }
    else
    {
        no_bits = qcoder_encode_eobflag_4x4( qcoder, 1, 0 );
    }
    return no_bits ;
}
#endif


void transform_B16( int **curr_blk ) // block to be transformed.
{
    int xx, i, j ;
    int temp1[16][16] ,temp2[16][16] ;

    for( i=0; i<16; i++ ) //  vertical transform
    {
        for( j=0; j<16; j++ )
        {
            temp1[i][j] = 0 ;
            for( xx=0; xx<16; xx++ )
            {
                temp1[i][j] += DCT_16[i][xx]*curr_blk[xx][j] ;
            }
        }
    }

    for( i=0; i<16; i++ ) // horizontal transform
    {
        for( j=0; j<16; j++ )
        {
            temp2[i][j] = 0 ;
            for( xx=0; xx<16; xx++ )
            {
                temp2[i][j] += temp1[i][xx]*DCT_16[j][xx] ;
            }
        }
    }

    for( i=0; i<16; i++ )
    {
        for( j=0; j<16; j++ )
        {
            curr_blk[i][j] = temp2[i][j] ;
        }
    }

}


void quant_B16( int qp,  int mode, int **curr_blk )
{
    int xx, yy;
    int val, temp;
    int qp_const;
    int intra    = 0;


    if ( mode>3 ) // mode 0..inter, mode 4.. intra
    {
        intra = 1;
    }

    if( intra )
        qp_const = ( 1<<15 )*10/31;
    else
        qp_const = ( 1<<15 )*10/62;

    for ( yy=0; yy<16; yy++ )
    {
        for ( xx=0; xx<16; xx++ )
        {
            val = curr_blk[yy][xx];
            temp = RFM_ABS( val );
            curr_blk[yy][xx] = sign( ( ( ( ( temp + ( 1<<13 ) ) >> 14 )* Q_TAB[qp]+qp_const )>>15 ), val ) ;
        }
    }
}

int scanquant_B16( int qp, int mode, int **curr_blk, int scrFlag, int *cbp )
{
    int  run;
    int  xx, yy;
    int  intra;
    int  icoef, ipos;
    int  coeff_cost    = 0;
    int  curr_val;
    int val, temp, shift, QPI;
    byte **pred;
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];
    int dc_pred=0;

#ifdef RDO_Q
    int levelTrellis[256] = {0} ;
    levelDataStruct levelData[256] ;
    int lambda_RDO_Q = img->lambda_mode ;
    int temp_blk[16][16] ;

    for( yy=0; yy<16; yy++ )
    {
        for( xx=0; xx<16; xx++ )
        {
            temp_blk[yy][xx] = curr_blk[yy][xx] ;
        }
    }
#endif

    shift = IQ_SHIFT[qp];
    QPI   = IQ_TAB[qp];
    *cbp = 0 ;

    intra=0;
    if( mode>3 )
        intra=1;

#ifdef RDO_Q
    if( input->UseRDO_Q16 )
    {
        RDO_Q_init16x16( temp_blk, qp, intra, levelData ) ;
        RDO_Quant16x16( levelData, levelTrellis, intra, lambda_RDO_Q ) ;
    }
    else
    {
        quant_B16( qp, mode, curr_blk );
    }
#else
    quant_B16( qp, mode, curr_blk );
#endif


    mode %= 4;

    if( intra )
    {
        pred=intra_pred;
        curr_blk[0][0] = currMB->y_16x16_dc_diff;
        dc_pred = currMB->y_16x16_dc_pred;
    }
    else
        pred=inter_pred;

    for ( xx=0; xx<257; xx++ )
    {
        img->cofAC16x16[xx][0]=img->cofAC16x16[xx][1] = 0;
    }


    run  = -1;
    ipos = 0;

    for ( icoef=0; icoef<256; icoef++ )
    {
        run++;
        xx = ZIGZAG_SCAN_16x16[1 /*img->picture_structure*/][icoef][0];
        yy = ZIGZAG_SCAN_16x16[1 /*img->picture_structure*/][icoef][1];

#ifdef RDO_Q
        if( input->UseRDO_Q16 )
        {
            if( !xx&&!yy&&intra )
            {
                curr_val = curr_blk[yy][xx] ;
            }
            else
            {
                curr_val = sign( levelTrellis[icoef],curr_blk[yy][xx] ) ;
            }

            if( curr_val==0 )
            {
                curr_blk[yy][xx] = 0 ;
            }
        }
        else
        {
            curr_val = curr_blk[yy][xx];
        }
#else
        curr_val = curr_blk[yy][xx];
#endif

        if ( curr_val != 0 )
        {

            img->cofAC16x16[ipos][0] = curr_val;
            img->cofAC16x16[ipos][1] = run;


            if ( scrFlag && RFM_ABS( img->cofAC16x16[ipos][0] )==1 )
                coeff_cost +=( scrFlag==1 )? 1 : RF_COEFF_COST[run];
            else
                coeff_cost += MAX_VALUE; // block has to be saved

            val = curr_val ;
            if ( intra&&!xx&&!yy )
                val += dc_pred;

            temp = sign( ( RFM_ABS( val )*QPI+( 1<<( shift-2 ) ) )>>( shift-1 ),val ); // dequantization
            curr_blk[yy][xx] = temp;

            run = -1;
            ipos++;
        }
        else
        {
            if ( intra&&!xx&!yy )
            {
                val = dc_pred;
                temp = sign( ( RFM_ABS( val )*QPI+( 1<<( shift-2 ) ) )>>( shift-1 ),val ); // dequantization
                curr_blk[yy][xx] = temp;
            }
        }
    }

    if ( ipos>0 )
    {
        *cbp = 1 ;
    }

    inv_transform_B16( curr_blk );

    for( yy=0; yy<16; yy++ )
    {
        for( xx=0; xx<16; xx++ )
        {
            p_img_y_rec[img->pix_y+yy][img->pix_x+xx] = RFM_CLIP3( ( curr_blk[yy][xx]+( pred )[yy][xx] ),0,255 ) ;
        }
    }

    return coeff_cost;
}


void inv_transform_B16( int **curr_blk )
{
    int xx, i, j ;
    int temp1[16][16] ,temp2[16][16] ;

    for( i=0; i<16; i++ )
    {
        for( j=0; j<16; j++ )
        {
            temp1[i][j] = 0 ;
            for( xx=0; xx<16; xx++ )
            {
                temp1[i][j] += DCT_16[xx][i]*curr_blk[xx][j] ;
            }
        }
    }

    for( i=0; i<16; i++ )
    {
        for( j=0; j<16; j++ )
        {
            temp2[i][j] = 0 ;
            for( xx=0; xx<16; xx++ )
            {
                temp2[i][j] += temp1[i][xx]*DCT_16[xx][j] ;
            }
        }
    }

    for( i=0; i<16; i++ )
    {
        for( j=0; j<16; j++ )
        {
            curr_blk[i][j] = sign( ( RFM_ABS( temp2[i][j] ) + ( 1<<14 ) )>>15,temp2[i][j] ) ;
        }
    }
}


void transform_b4( int curr_blk[B4_SIZE][B4_SIZE] )
{
    int i, j;
    int temp1[4], temp2[4], temp ;

    // right
    for( i=0; i<4; i++ )
    {
        // step 1
        temp1[0] = curr_blk[i][0] + curr_blk[i][3] ;
        temp1[3] = curr_blk[i][0] - curr_blk[i][3] ;
        temp1[1] = curr_blk[i][1] + curr_blk[i][2] ;
        temp1[2] = curr_blk[i][1] - curr_blk[i][2] ;

        // step 2
        temp2[0] = temp1[0] + temp1[1] ;
        temp2[2] = temp1[0] - temp1[1] ;
        temp     = temp1[2] + temp1[3] ;
        temp     = ( temp*69 )>>7 ;
        temp2[1] = temp + ( temp1[3]*98>>7 ) ;
        temp2[3] = temp - ( temp1[2]*236>>7 ) ;

        curr_blk[i][0] = temp2[0] ;
        curr_blk[i][1] = temp2[1] ;
        curr_blk[i][2] = temp2[2] ;
        curr_blk[i][3] = temp2[3] ;
    }

    // left
    for( i=0; i<4; i++ )
    {
        // step 1
        temp1[0] = curr_blk[0][i] + curr_blk[3][i] ;
        temp1[3] = curr_blk[0][i] - curr_blk[3][i] ;
        temp1[1] = curr_blk[1][i] + curr_blk[2][i] ;
        temp1[2] = curr_blk[1][i] - curr_blk[2][i] ;

        // step 2
        temp2[0] = temp1[0] + temp1[1] ;
        temp2[2] = temp1[0] - temp1[1] ;
        temp     = temp1[2] + temp1[3] ;
        temp     = ( temp*69 )>>7 ;
        temp2[1] = temp + ( temp1[3]*98>>7 ) ;
        temp2[3] = temp - ( temp1[2]*236>>7 ) ;


        for( j=0; j<4; j++ )
        {
            if( temp2[j]>0 )
            {
                curr_blk[j][i] = ( temp2[j]+2 )>>2 ;
            }
            else
            {
                curr_blk[j][i] = -( ( -temp2[j]+2 )>>2 ) ;
            }
        }
    }
}

void quant_b4( int qp,int mode, int curr_blk[B4_SIZE][B4_SIZE],int y_left,int x_top )
{
    int i, j;
    int val, temp;
    int qp_const;
    int intra=0;
    int qdiff;

    if ( mode>3 )
    {
        intra = 1;
    }

    if ( intra )
        qp_const = ( 1<<15 )/3;
    else
        qp_const = ( 1<<15 )/6;

#ifdef RDO_Q
    if( input->UseRDO_Q4 )
    {
        val = curr_blk[0][0];
        temp = RFM_ABS( val );
        curr_blk[0][0] = sign( ( ( temp * Q_TAB[qp]+qp_const )>>15 ), val );
    }
    else
    {
        if ( !input->AdaptiveRounding )
        {
            for ( j=0; j<4; j++ )
            {
                for ( i=0; i<4; i++ )
                {
                    val = curr_blk[j][i];
                    temp = RFM_ABS( val );
                    curr_blk[j][i] = sign( ( ( temp * Q_TAB[qp]+qp_const )>>15 ), val );
                }
            }
        }
        else
        {
            for ( j=0; j<4; j++ )
            {
                for ( i=0; i<4; i++ )
                {
                    val = curr_blk[j][i];
                    temp = RFM_ABS( val );
                    qp_const = qoffset4x4[img->type][intra][j+y_left][i+x_top];
                    curr_blk[j][i] = sign( ( ( temp * Q_TAB[qp]+qp_const )>>15 ), val ) ;
                    qdiff=temp*Q_TAB[qp]-( RFM_ABS( curr_blk[j][i] )<<15 );
                    img->qadjust4x4[j+y_left][i+x_top] = ( curr_blk[j][i]==0 ) ? 0 :( ( input->AdaptRndWeight[img->type]*qdiff + ( 1<<15 ) ) >> 16 );
                }
            }
        }
    }
#else
    for ( j=0; j<4; j++ )
    {
        for ( i=0; i<4; i++ )
        {
            val = curr_blk[j][i];
            temp = RFM_ABS( val );
            curr_blk[j][i] = sign( ( ( temp * Q_TAB[qp]+qp_const )>>15 ), val );
        }
    }
#endif
}

void Dequant_b4( int qp, int curr_blk[B4_SIZE][B4_SIZE] )
{
    int i, j;
    int val;
    int shift, QPI;

    for ( j=0; j<4; j++ )
    {
        for ( i=0; i<4; i++ )
        {
            val  = curr_blk[j][i];
            shift = IQ_SHIFT[qp];
            QPI   = IQ_TAB[qp];
            curr_blk[j][i] = sign( ( RFM_ABS( val )*QPI+( 1<<( shift-2 ) ) )>>( shift-1 ),val );
        }
    }
}

int zigzag_scan_b4( int *ACLevel, int *ACRun, int curr_blk[B4_SIZE][B4_SIZE] )
{

    int  icoef, ipos;
    int  xx, yy;
    int  run;

    for ( xx=0; xx<17; xx++ )
        ACLevel[xx]= ACRun[xx] = 0;

    run  = -1;
    ipos = 0;

    for ( icoef=0; icoef<16; icoef++ )
    {
        run++;
        xx = ZIGZAG_SCAN_4x4[1 /*img->picture_structure*/][icoef][0];
        yy = ZIGZAG_SCAN_4x4[1 /*img->picture_structure*/][icoef][1];

        if ( curr_blk[yy][xx]!= 0 )
        {
            ACLevel[ipos] = curr_blk[yy][xx];
            ACRun[ipos]   = run;
            run = -1;
            ipos++;
        }
    }

    return 0;
}

void inv_transform_b4( int curr_blk[B4_SIZE][B4_SIZE] )
{
    int i, j ;
    int temp1[4], temp ;

    for( i=0; i<4; i++ )
    {
        temp1[0] = curr_blk[i][0] + curr_blk[i][2] ;
        temp1[2] = curr_blk[i][0] - curr_blk[i][2] ;
        temp     = ( curr_blk[i][1] + curr_blk[i][3] )*69>>7 ;
        temp1[1] = temp + ( curr_blk[i][1]*98>>7 ) ;
        temp1[3] = temp - ( curr_blk[i][3]*236>>7 ) ;

        curr_blk[i][0] = temp1[0] + temp1[1] ;
        curr_blk[i][3] = temp1[0] - temp1[1] ;
        curr_blk[i][1] = temp1[2] + temp1[3] ;
        curr_blk[i][2] = temp1[2] - temp1[3] ;
    }
    for( i=0; i<4; i++ )
    {
        temp1[0] = curr_blk[0][i] + curr_blk[2][i] ;
        temp1[2] = curr_blk[0][i] - curr_blk[2][i] ;
        temp     = ( curr_blk[1][i] + curr_blk[3][i] )*69>>7 ;
        temp1[1] = temp + ( curr_blk[1][i]*98>>7 ) ;
        temp1[3] = temp - ( curr_blk[3][i]*236>>7 ) ;

        curr_blk[0][i] = temp1[0] + temp1[1] ;
        curr_blk[3][i] = temp1[0] - temp1[1] ;
        curr_blk[1][i] = temp1[2] + temp1[3] ;
        curr_blk[2][i] = temp1[2] - temp1[3] ;

        for( j=0; j<4; j++ )
        {
            if( curr_blk[j][i]>0 )
            {
                curr_blk[j][i] = ( curr_blk[j][i]+4 )>>3 ;
            }
            else
            {
                curr_blk[j][i] = -( ( -curr_blk[j][i]+4 )>>3 ) ;
            }
        }
    }
}

int trans_scanquant_b4 ( int qp, int mode,int block8x8, int block4x4, int **curr_blk, int ACLevel_4x4[17], int ACRun_4x4[17] )
{
    int  xx, yy, x,y,i;
    int j,k,m;
    int  b8_y  = ( block8x8 / 2 ) << 3;
    int  b8_x  = ( block8x8 % 2 ) << 3;
    int  b4_y  = ( block4x4/2 )<<2;
    int  b4_x  = ( block4x4%2 )<<2;

    int  intra;
    int  curr_val;
    int  curr_blk_4x4[B4_SIZE][B4_SIZE];
    byte **pred;
    macroblock_t * currMB = &img->mb_data[img->curr_mb_nr];

#ifdef RDO_Q
    levelDataStruct levelData[16] ;
    int lambda = img->lambda_mode ;
    int levelTrellis[16] = {0} ;
#endif

    for( y=0; y<4; y++ )
    {
        for( x=0; x<4; x++ )
        {
            yy = y + b4_y;
            xx = x + b4_x;
            curr_blk_4x4[y][x] = curr_blk[yy][xx];
        }
    }

    transform_b4( curr_blk_4x4 );
    quant_b4( qp,mode, curr_blk_4x4, b8_y+b4_y, b8_x+b4_x );

    i=block8x8/2;
    j=block8x8%2;
    k=block4x4/2;
    m=block4x4%2;
    currMB->y_4x4_dc_diff[i][j][k][m]=currMB->y_4x4_dc[i][j][k][m]=curr_blk_4x4[0][0];
    currMB->y_4x4_dc_pred[i][j][k][m]=0;
    decide_y_intra_b4_mode( 8*i+4*j+2*k+m );

#ifdef RDO_Q
    if( input->UseRDO_Q4 )
    {
        cs_ptr_t cs_sb = create_coding_state();
        int icoef;
        store_coding_state( cs_sb );
#if INTRA_MODE_ADAPTIVE
        if( mode == 4 )
            write_luma_intra_mode( currMB->b4mode[block8x8/2][block8x8%2][block4x4/2][block4x4%2], block8x8,block4x4 );
#endif
		RDO_Q_init4x4( curr_blk_4x4, qp, ( mode>3 ), block8x8, block4x4, levelData ) ;
        RDO_Quant4x4( levelData, levelTrellis, block8x8, block4x4, ( mode>3 ), lambda ) ;
        // inv_scan
        for( icoef=1; icoef<16; icoef++ )
        {
            xx = ZIGZAG_SCAN_4x4[1 /*img->picture_structure*/][icoef][0];
            yy = ZIGZAG_SCAN_4x4[1 /*img->picture_structure*/][icoef][1];
            curr_blk_4x4[yy][xx] = sign( levelTrellis[icoef],curr_blk_4x4[yy][xx] ) ;
        }
        reset_coding_state( cs_sb );
        delete_coding_state( cs_sb );
    }
#endif

    intra=0;
    if( mode>3 )
        intra=1;
    mode %= 4;
    if( intra )
    {
        pred=intra_pred;
        curr_blk_4x4[0][0] = currMB->y_4x4_dc_diff[block8x8/2][block8x8%2][block4x4/2][block4x4%2];
    }
    else
        pred=inter_pred;

    for ( xx=0; xx<17; xx++ )
        ACRun_4x4[xx] = ACLevel_4x4[xx] = 0;

    zigzag_scan_b4( ACLevel_4x4,ACRun_4x4, curr_blk_4x4 );

    for ( xx=0; xx<17; xx++ )
    {
        img->cofAC[block8x8][block4x4][0][xx] = ACLevel_4x4[xx];
        img->cofAC[block8x8][block4x4][1][xx] = ACRun_4x4[xx];
    }

    if( intra )
    {
        curr_blk_4x4[0][0] = currMB->y_4x4_dc[i][j][k][m];
    }
    Dequant_b4( qp,curr_blk_4x4 );
    inv_transform_b4( curr_blk_4x4 );

    for( yy=0; yy<4; yy++ )
    {
        for( xx=0; xx<4; xx++ )
        {
            curr_val = ( pred )[b8_y+b4_y+yy][b8_x+b4_x+xx] + curr_blk_4x4[yy][xx];
            curr_blk[b4_y+yy][b4_x+xx] = RFM_CLIP3( curr_val,0,255/*max_pel_value*/ );
            p_img_y_rec[img->pix_y+b8_y+b4_y+yy][img->pix_x+b8_x+b4_x+xx] = curr_blk[b4_y+yy][b4_x+xx];
        }
    }
    return 0;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void get_inter_pred_y_block( int block, int mode, macroblock_t * currMB )
{
#if QUARTER_PIXEL
    static const int positionQ[4][4] = {{0, 4, 1, 5}, {6, 8, 14, 9}, {2, 12, 3, 13}, {7, 10, 15, 11}};
#else
    static const int postion[2][2] = {{0, 1}, {2, 3}};
#endif
    int i, j, ref_idx, pic_y, pic_x, dir, x, y, x_offset[2], y_offset[2];
    int blk4x4_y, blk4x4_x;
    int pred_x, pred_y;
    int pos[2];
    byte **ref_frm[2];
    int dx,dy;
    mv_t mv[2];

    j= block/2;
    i= block%2;
    pic_y  = img->pix_y + 8 * j;
    pic_x  = img->pix_x + 8 * i;
    pred_y = 8 * j;
    pred_x = 8 * i;

    if( input->ABTen && input->InterABTen && mode == INTER4x4 )
    {
        for ( blk4x4_y=0; blk4x4_y<=1; blk4x4_y++ )
        {
            for ( blk4x4_x=0; blk4x4_x<=1; blk4x4_x++ )
            {
                if ( currMB->b4_ref[2*j+i][2*blk4x4_y+blk4x4_x] != BI )
                {
                    ref_idx = currMB->b4_ref[2*j+i][2*blk4x4_y+blk4x4_x];
                    mv[0]   = img->mv_4x4[ref_idx][2*j+i][2*blk4x4_y+blk4x4_x];
#if QUARTER_PIXEL
                    dy=mv[0].y&3;    //dw 20110808
                    dx=mv[0].x&3;    //dw 20110808

                    pos[0]  = positionQ[dy][dx];  //dw 20110808
#else
                    dy=mv[0].y&1;
                    dx=mv[0].x&1;

                    pos[0]  = postion[dy][dx];
#endif
                    if ( !pos[0] )
                    {
                        ref_frm[0] = img_y_rec_space[ref_idx];
                    }
                    else
                    {
                        ref_frm[0] = y_up_sampling[ref_idx][pos[0]-1];
                    }
#if QUARTER_PIXEL
                    y_offset[0] = ( mv[0].y-dy )/4 + pic_y + blk4x4_y*4 + IMG_PAD_SIZE; //dw 20110808
                    x_offset[0] = ( mv[0].x-dx )/4 + pic_x + blk4x4_x*4 + IMG_PAD_SIZE; //dw 20110808
#else
                    y_offset[0] = ( mv[0].y-dy )/2 + pic_y + blk4x4_y*4 + IMG_PAD_SIZE;
                    x_offset[0] = ( mv[0].x-dx )/2 + pic_x + blk4x4_x*4 + IMG_PAD_SIZE;
#endif
                    for ( y = 0; y < B4_SIZE; y++ )
                    {
                        for ( x = 0; x < B4_SIZE; x++ )
                        {
                            inter_pred[pred_y+blk4x4_y*4+y][pred_x+blk4x4_x*4+x] = ref_frm[0][RFM_CLIP3( y_offset[0] + y,0,img->p_height-1 )][RFM_CLIP3( x_offset[0] + x,0,img->p_width-1 )];
                        }
                    }
                }
                else
                {
                    for ( dir = 0; dir < BI; dir++ )
                    {

                        if ( dir==FW )  //
                            mv[dir] = img->bi_mv_4x4[2*j+i][2*blk4x4_y+blk4x4_x].fw_mv;
                        else          //  BW
                            mv[dir] = img->bi_mv_4x4[2*j+i][2*blk4x4_y+blk4x4_x].bw_mv;
#if QUARTER_PIXEL
                        dy=mv[dir].y&3;  //dw 20110808
                        dx=mv[dir].x&3;  //dw 20110808

                        pos[dir] = positionQ[dy][dx];  //dw 20110808
#else
                        dy=mv[dir].y&1;
                        dx=mv[dir].x&1;

                        pos[dir] = postion[dy][dx];
#endif
                        if ( !pos[dir] )
                            ref_frm[dir] = img_y_rec_space[dir];
                        else
                            ref_frm[dir] = y_up_sampling[dir][pos[dir]-1];

#if QUARTER_PIXEL
                        y_offset[dir] = ( mv[dir].y-dy )/4 + pic_y + blk4x4_y*4 + IMG_PAD_SIZE; //dw 20110808
                        x_offset[dir] = ( mv[dir].x-dx )/4 + pic_x + blk4x4_x*4 + IMG_PAD_SIZE; //dw 20110808
#else
                        y_offset[dir] = ( mv[dir].y-dy )/2 + pic_y + blk4x4_y*4 + IMG_PAD_SIZE;
                        x_offset[dir] = ( mv[dir].x-dx )/2 + pic_x + blk4x4_x*4 + IMG_PAD_SIZE;
#endif
                    }

                    for ( y = 0; y < B4_SIZE; y++ )
                    {
                        for ( x = 0; x < B4_SIZE; x++ )
                        {
                            inter_pred[pred_y+blk4x4_y*4+y][pred_x+blk4x4_x*4+x] = ( ref_frm[FW][RFM_CLIP3( y_offset[FW] + y,0,img->p_height-1 )][RFM_CLIP3( x_offset[FW] + x,0,img->p_width-1 )] + ref_frm[BW][RFM_CLIP3( y_offset[BW] + y,0,img->p_height-1 )][RFM_CLIP3( x_offset[BW] + x,0,img->p_width-1 )] + 1 )>>1;
                        }
                    }
                }//end else BI
            }//end for blk4x4_x
        }//end for blk4x4_y
    }//end vbs_enable
    else
    {
        if ( currMB->b8_ref[j][i] != BI )
        {
            ref_idx = currMB->b8_ref[j][i];
            mv[0]   = img->mv[ref_idx][mode][j][i];
#if QUARTER_PIXEL
            dy=mv[0].y&3;  //dw 20110808
            dx=mv[0].x&3;  //dw 20110808

            pos[0]  = positionQ[dy][dx];  //dw 20110808
#else
            dy=mv[0].y&1;
            dx=mv[0].x&1;
            //pos[0]  = postion[RFM_ABS(mv[0].y) & 1][RFM_ABS(mv[0].x) & 1];
            pos[0]  = postion[dy][dx];
#endif
            if ( !pos[0] )
            {
                ref_frm[0] = img_y_rec_space[ref_idx];
            }
            else
            {
                ref_frm[0] = y_up_sampling[ref_idx][pos[0]-1];
            }
#if QUARTER_PIXEL
            y_offset[0] = ( mv[0].y-dy )/4 + pic_y + IMG_PAD_SIZE; //dw 20110808
            x_offset[0] = ( mv[0].x-dx )/4 + pic_x + IMG_PAD_SIZE; //dw 20110808
#else
            y_offset[0] = ( mv[0].y-dy )/2 + pic_y + IMG_PAD_SIZE;
            x_offset[0] = ( mv[0].x-dx )/2 + pic_x + IMG_PAD_SIZE;
#endif
            for ( y = 0; y < B8_SIZE; y++ )
            {
                for ( x = 0; x < B8_SIZE; x++ )
                {
                    inter_pred[pred_y+y][pred_x+x] = ref_frm[0][RFM_CLIP3( y_offset[0] + y,0,img->p_height-1 )][RFM_CLIP3( x_offset[0] + x,0,img->p_width-1 )];
                }
            }
        }
        else
        {
            for ( dir = 0; dir < BI; dir++ )
            {
                //mv[dir]  = img->mv[dir][mode][j][i];
                if ( dir==FW )  //
                {
                    mv[dir] = img->bi_mv[mode][j][i].fw_mv;
                }
                else          //  BW
                {
                    mv[dir] = img->bi_mv[mode][j][i].bw_mv;
                }
#if QUARTER_PIXEL
                dy=mv[dir].y&3;  //dw 20110808
                dx=mv[dir].x&3;  //dw 20110808

                pos[dir] = positionQ[dy][dx];  //dw 20110808
#else
                dy=mv[dir].y&1;
                dx=mv[dir].x&1;

                pos[dir] = postion[dy][dx];
#endif
                if ( !pos[dir] )
                {
                    ref_frm[dir] = img_y_rec_space[dir];
                }
                else
                {
                    ref_frm[dir] = y_up_sampling[dir][pos[dir]-1];
                }
#if QUARTER_PIXEL
                y_offset[dir] = ( mv[dir].y-dy )/4 + pic_y + IMG_PAD_SIZE; //dw 20110808
                x_offset[dir] = ( mv[dir].x-dx )/4 + pic_x + IMG_PAD_SIZE; //dw 20110808
#else
                y_offset[dir] = ( mv[dir].y-dy )/2 + pic_y + IMG_PAD_SIZE;
                x_offset[dir] = ( mv[dir].x-dx )/2 + pic_x + IMG_PAD_SIZE;
#endif
            }

            for ( y = 0; y < B8_SIZE; y++ )
            {
                for ( x = 0; x < B8_SIZE; x++ )
                {
                    inter_pred[pred_y+y][pred_x+x] = ( ref_frm[FW][RFM_CLIP3( y_offset[FW] + y,0,img->p_height-1 )][RFM_CLIP3( x_offset[FW] + x,0,img->p_width-1 )] + ref_frm[BW][RFM_CLIP3( y_offset[BW] + y,0,img->p_height-1 )][RFM_CLIP3( x_offset[BW] + x,0,img->p_width-1 )] + 1 )>>1;
                }
            }
        }//end one block
    }//end vbs_enable
}

